#include "../../include/event/event_loop.h"
#include <atomic>
#include <condition_variable>
#include <queue>

namespace event
{
class EventLoopData
{
private:
  friend class EventLoop;

  std::queue<EventInterfaceSharedPtr> event_queue_;
  std::mutex mutex_;
  std::condition_variable cv_;
  std::atomic_bool finish_exec_{false};
};
}// namespace event

namespace event
{
EventLoop::EventLoop()
    : d_(std::make_unique<EventLoopData>())
{
}
void EventLoop::exec()
{
  d_->finish_exec_ = false;
  while (true)
  {
    std::unique_lock<std::mutex> locker(d_->mutex_);
    d_->cv_.wait(locker, [this] {
      return !d_->event_queue_.empty();
    });
    if (d_->finish_exec_)
    {
      break;
    }
    EventInterfaceSharedPtr front = d_->event_queue_.front();
    d_->event_queue_.pop();
    locker.unlock();

    front->run();
  }
}
void EventLoop::stopExec()
{
  d_->finish_exec_ = true;
  std::unique_lock<std::mutex> locker(d_->mutex_);
  d_->cv_.notify_one();
}
void EventLoop::execOnce()
{
  std::unique_lock<std::mutex> locker(d_->mutex_);
  if (d_->event_queue_.empty())
  {
    return;
  }
  EventInterfaceSharedPtr front = d_->event_queue_.front();
  d_->event_queue_.pop();
  locker.unlock();

  front->run();
}
void EventLoop::addEvent(const EventInterfaceSharedPtr &event)
{
  std::lock_guard<std::mutex> lock_guard(d_->mutex_);
  d_->event_queue_.emplace(event);
  d_->cv_.notify_one();
}
void EventLoop::clearEvent()
{
  std::lock_guard<std::mutex> lock_guard(d_->mutex_);
  while (!d_->event_queue_.empty())
  {
    d_->event_queue_.pop();
  }
}
EventLoop::~EventLoop() = default;

}// namespace event
